#!/usr/bin/env bash

set -eu

common_abspath() (
  echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
)

# Benchmark a command.
#
# $1: command to benchmark
# $2: where to append write results to. Default: /dev/null.
#
# Result format:
#
# cmd <command run>
# time <time in seconds to finish>
# exit_status <exit status>
common_bench_cmd() (
  cmd="$1"
  results_file="${2:-/dev/null}"
  printf 'cmd ' >> "$results_file"
  env time --append -f 'time %e' --output="$results_file" "${common_root_dir}/eeval" -a "$cmd" "$results_file"
  printf "exit_status $?\n" >> "$results_file"
)


# Handle options common across multiple scripts.
common_getopts_case() {
  case "$1" in
    a)
      common_arch="$OPTARG"
      ;;
    g)
      common_gem5=true
      ;;
    L)
      common_linux_variant="$OPTARG"
      ;;
    M)
      common_gem5_variant="$OPTARG"
      ;;
    N)
      common_gem5_worktree="$OPTARG"
      ;;
    n)
      common_run_id="$OPTARG"
      ;;
    Q)
      common_qemu_variant="$OPTARG"
      ;;
    s)
      common_suffix="$OPTARG"
      ;;
    t)
      common_gem5_build_type="$OPTARG"
      ;;
    ?)
      exit 2
      ;;
  esac
}
common_getopts_flags='a:gL:M:N:n:Q:s:t:'

# Setup several variables and do other initialization common to most scripts.
# Typically done after getting inputs from the command line arguments.
common_setup() {
  case "$common_arch" in
    a|arm)
      common_arch=arm
      common_gem5_arch=ARM
      ;;
    A|aarch64)
      common_arch=aarch64
      common_gem5_arch=ARM
      ;;
    m|mips64)
      common_arch=mips64
      ;;
    x|x86_64)
      common_arch=x86_64
      common_gem5_arch=X86
      ;;
    *)
      printf "unknown arch: ${common_arch}\n" 1>&2
      exit 2
      ;;
  esac
  common_buildroot_dir="${common_root_dir}/buildroot"
  common_arch_dir="$common_arch"
  if [ -n "$common_suffix" ]; then
    common_arch_dir="${common_arch_dir}-${common_suffix}"
  fi
  common_out_arch_dir="${common_out_dir}/${common_arch_dir}"
    common_buildroot_out_dir="${common_out_arch_dir}/buildroot"
      common_build_dir="${common_buildroot_out_dir}/build"
        common_linux_custom_dir="${common_build_dir}/linux-custom"
          common_linux_variant_dir="${common_linux_custom_dir}.${common_linux_variant}"
            common_vmlinux="${common_linux_variant_dir}/vmlinux"
        common_qemu_custom_dir="${common_build_dir}/host-qemu-custom"
          common_qemu_guest_variant_dir="${common_qemu_custom_dir}.${common_qemu_variant}"
          common_qemu_variant_dir="${common_qemu_custom_dir}.${common_qemu_variant}"
            common_qemu_exec="${common_qemu_variant_dir}/${common_arch}-softmmu/qemu-system-${common_arch}"
        common_qemu_guest_custom_dir="${common_build_dir}/qemu-custom"
      common_host_dir="${common_buildroot_out_dir}/host"
      common_images_dir="${common_buildroot_out_dir}/images"
        common_qcow2_file="${common_images_dir}/rootfs.ext2.qcow2"
      common_staging_dir="${common_buildroot_out_dir}/staging"
      common_target_dir="${common_buildroot_out_dir}/target"
    common_gem5_run_dir="${common_out_arch_dir}/gem5/${common_run_id}"
      common_m5out_dir="${common_gem5_run_dir}/m5out"
        common_trace_txt_file="${common_m5out_dir}/trace.txt"
      common_gem5_termout_file="${common_gem5_run_dir}/termout.txt"
    common_qemu_run_dir="${common_out_arch_dir}/qemu/${common_run_id}"
      common_qemu_termout_file="${common_qemu_run_dir}/termout.txt"
      common_qemu_rrfile="${common_qemu_run_dir}/rrfile"
  common_gem5_out_dir="${common_dir}/gem5/${common_gem5_variant}"
    common_gem5_m5term="${common_gem5_out_dir}/m5term"
    common_gem5_build_dir="${common_gem5_out_dir}/build"
      common_gem5_exec="${common_gem5_build_dir}/${common_gem5_arch}/gem5.${common_gem5_build_type}"
    common_gem5_system_dir="${common_gem5_out_dir}/system"
  if [ -n "$common_gem5_worktree" ]; then
    common_gem5_src_dir="${common_gem5_non_default_src_root_dir}/${common_gem5_worktree}"
  else
    common_gem5_src_dir="$common_gem5_default_src_dir"
  fi
  if "$common_gem5"; then
    common_exec="$common_gem5_exec"
    common_run_dir="$common_gem5_run_dir"
    common_termout_file="$common_gem5_termout_file"
  else
    common_exec="$common_qemu_exec"
    common_run_dir="$common_qemu_run_dir"
    common_termout_file="$common_qemu_termout_file"
  fi
  case "$common_arch" in
    arm)
      common_linux_image=arch/arm/boot/zImage
      ;;
    aarch64)
      common_linux_image=arch/arm64/boot/Image
      ;;
    mips64)
      common_linux_image=vmlinux
      ;;
    x86_64)
      common_linux_image=arch/x86/boot/bzImage
      ;;
  esac
  common_linux_image="${common_linux_variant_dir}/${common_linux_image}"

  # Ports.
  common_run_id_number="$(echo "$common_run_id" | cut -d . -f 2)"
  if "$common_gem5"; then
    common_gem5_telnet_port="$((3456 + $common_run_id_number))"
    common_gdb_port="$((7000 + $common_run_id_number))"
  else
    common_qemu_base_port="$((45454 + 10 * $common_run_id_number))"
    common_qemu_monitor_port="$(($common_qemu_base_port + 0))"
    common_qemu_hostfwd_generic_port="$(($common_qemu_base_port + 1))"
    common_qemu_hostfwd_ssh_port="$(($common_qemu_base_port + 2))"
    common_qemu_gdb_port="$(($common_qemu_base_port + 3))"
    common_gdb_port="$common_qemu_gdb_port"
  fi
}

common_mkdir() (
  mkdir -p \
    "$common_build_dir" \
    "$common_gem5_out_dir" \
    "$common_gem5_run_dir" \
    "$common_qemu_run_dir" \
    "$common_9p_dir" \
  ;
)

# Default paths.
common_root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  common_data_dir="${common_root_dir}/data"
    common_9p_dir="${common_data_dir}/9p"
    common_gem5_non_default_src_root_dir="${common_data_dir}/gem5"
    common_gem5_readfile_file="${common_data_dir}/readfile"
  common_gem5_default_src_dir="${common_root_dir}/gem5/gem5"
  common_out_dir="${common_root_dir}/out"
    common_bench_boot="${common_out_dir}/bench-boot.txt"
    common_dir="${common_out_dir}/common"

# Other default variables.
common_arch=x86_64
common_gem5=false
common_gem5_build_type=opt
common_gem5_cpt_pref='^cpt\.'
common_gem5_variant=default
common_gem5_worktree=
common_linux_variant=default
common_qemu_variant=default
common_run_id=0
common_sha="$(git log -1 --format="%H")"
common_suffix=

f="${common_data_dir}/config"
if [ -f "$f" ]; then
  . "$f"
fi
